#ifndef DTU_MODBUS_H
#define DTU_MODBUS_H

#include "dtu_common.h"

/* Modbus协议模式 */
typedef enum {
    MODBUS_MODE_RTU = 0,      /* RTU模式 */
    MODBUS_MODE_ASCII = 1     /* ASCII模式 */
} modbus_mode_t;

/* Modbus功能码 */
typedef enum {
    MODBUS_FC_READ_COILS = 0x01,                    /* 读线圈 */
    MODBUS_FC_READ_DISCRETE_INPUTS = 0x02,          /* 读离散输入 */
    MODBUS_FC_READ_HOLDING_REGISTERS = 0x03,        /* 读保持寄存器 */
    MODBUS_FC_READ_INPUT_REGISTERS = 0x04,          /* 读输入寄存器 */
    MODBUS_FC_WRITE_SINGLE_COIL = 0x05,            /* 写单个线圈 */
    MODBUS_FC_WRITE_SINGLE_REGISTER = 0x06,         /* 写单个寄存器 */
    MODBUS_FC_WRITE_MULTIPLE_COILS = 0x0F,         /* 写多个线圈 */
    MODBUS_FC_WRITE_MULTIPLE_REGISTERS = 0x10       /* 写多个寄存器 */
} modbus_function_code_t;

/* Modbus异常码 */
typedef enum {
    MODBUS_EXCEPTION_NONE = 0x00,                   /* 无异常 */
    MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01,       /* 非法功能码 */
    MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS = 0x02,   /* 非法数据地址 */
    MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE = 0x03,     /* 非法数据值 */
    MODBUS_EXCEPTION_SLAVE_DEVICE_FAILURE = 0x04,   /* 从设备故障 */
    MODBUS_EXCEPTION_ACKNOWLEDGE = 0x05,             /* 确认 */
    MODBUS_EXCEPTION_SLAVE_DEVICE_BUSY = 0x06,      /* 从设备忙 */
    MODBUS_EXCEPTION_MEMORY_PARITY_ERROR = 0x08,    /* 内存奇偶校验错误 */
    MODBUS_EXCEPTION_GATEWAY_PATH_UNAVAILABLE = 0x0A, /* 网关路径不可用 */
    MODBUS_EXCEPTION_GATEWAY_TARGET_FAILED = 0x0B   /* 网关目标设备响应失败 */
} modbus_exception_t;

/* Modbus请求结构 */
typedef struct {
    uint8_t slave_id;         /* 从站地址 */
    modbus_function_code_t function_code; /* 功能码 */
    uint16_t start_address;   /* 起始地址 */
    uint16_t quantity;        /* 数量 */
    uint8_t* data;           /* 数据指针 */
    size_t data_length;      /* 数据长度 */
} modbus_request_t;

/* Modbus响应结构 */
typedef struct {
    uint8_t slave_id;         /* 从站地址 */
    modbus_function_code_t function_code; /* 功能码 */
    uint8_t byte_count;       /* 字节数 */
    uint8_t* data;           /* 数据指针 */
    size_t data_length;      /* 数据长度 */
    modbus_exception_t exception; /* 异常码 */
} modbus_response_t;

/* Modbus帧结构 */
typedef struct {
    uint8_t* frame;          /* 帧数据 */
    size_t frame_length;     /* 帧长度 */
    uint16_t crc;            /* CRC校验值 */
    uint8_t lrc;             /* LRC校验值 */
} modbus_frame_t;

/* Modbus上下文结构 */
typedef struct {
    modbus_mode_t mode;       /* 协议模式 */
    serial_config_t serial_config; /* 串口配置 */
    int serial_fd;            /* 串口文件描述符 */
    uint8_t default_slave_id; /* 默认从站地址 */
    int response_timeout;     /* 响应超时时间(ms) */
    int frame_timeout;        /* 帧间超时时间(ms) */
    pthread_mutex_t mutex;    /* 互斥锁 */
    bool initialized;         /* 初始化标志 */
    uint32_t request_count;   /* 请求计数 */
    uint32_t response_count;  /* 响应计数 */
    uint32_t error_count;     /* 错误计数 */
    uint32_t timeout_count;   /* 超时计数 */
} modbus_context_t;

/* Modbus统计信息 */
typedef struct {
    uint32_t total_requests;  /* 总请求数 */
    uint32_t successful_requests; /* 成功请求数 */
    uint32_t failed_requests; /* 失败请求数 */
    uint32_t timeout_requests; /* 超时请求数 */
    uint32_t exception_requests; /* 异常请求数 */
    uint32_t crc_errors;      /* CRC错误数 */
    uint32_t frame_errors;    /* 帧错误数 */
    time_t last_request_time; /* 最后请求时间 */
} modbus_stats_t;

/* 函数声明 */

/**
 * @brief 初始化Modbus上下文
 * @param mode 协议模式
 * @param serial_config 串口配置
 * @return Modbus上下文指针，失败返回NULL
 */
modbus_context_t* dtu_modbus_init(modbus_mode_t mode, const serial_config_t* serial_config);

/**
 * @brief 销毁Modbus上下文
 * @param ctx Modbus上下文
 */
void dtu_modbus_cleanup(modbus_context_t* ctx);

/**
 * @brief 连接Modbus设备
 * @param ctx Modbus上下文
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_connect(modbus_context_t* ctx);

/**
 * @brief 断开Modbus连接
 * @param ctx Modbus上下文
 */
void dtu_modbus_disconnect(modbus_context_t* ctx);

/**
 * @brief 设置从站地址
 * @param ctx Modbus上下文
 * @param slave_id 从站地址
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_set_slave_id(modbus_context_t* ctx, uint8_t slave_id);

/**
 * @brief 设置响应超时时间
 * @param ctx Modbus上下文
 * @param timeout 超时时间(ms)
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_set_response_timeout(modbus_context_t* ctx, int timeout);

/**
 * @brief 读线圈
 * @param ctx Modbus上下文
 * @param slave_id 从站地址
 * @param start_address 起始地址
 * @param quantity 线圈数量
 * @param coils 输出线圈状态数组
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_read_coils(modbus_context_t* ctx, uint8_t slave_id,
                                  uint16_t start_address, uint16_t quantity, uint8_t* coils);

/**
 * @brief 读离散输入
 * @param ctx Modbus上下文
 * @param slave_id 从站地址
 * @param start_address 起始地址
 * @param quantity 输入数量
 * @param inputs 输出输入状态数组
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_read_discrete_inputs(modbus_context_t* ctx, uint8_t slave_id,
                                            uint16_t start_address, uint16_t quantity, uint8_t* inputs);

/**
 * @brief 读保持寄存器
 * @param ctx Modbus上下文
 * @param slave_id 从站地址
 * @param start_address 起始地址
 * @param quantity 寄存器数量
 * @param registers 输出寄存器值数组
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_read_holding_registers(modbus_context_t* ctx, uint8_t slave_id,
                                              uint16_t start_address, uint16_t quantity, uint16_t* registers);

/**
 * @brief 读输入寄存器
 * @param ctx Modbus上下文
 * @param slave_id 从站地址
 * @param start_address 起始地址
 * @param quantity 寄存器数量
 * @param registers 输出寄存器值数组
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_read_input_registers(modbus_context_t* ctx, uint8_t slave_id,
                                           uint16_t start_address, uint16_t quantity, uint16_t* registers);

/**
 * @brief 写单个线圈
 * @param ctx Modbus上下文
 * @param slave_id 从站地址
 * @param address 线圈地址
 * @param value 线圈值
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_write_single_coil(modbus_context_t* ctx, uint8_t slave_id,
                                         uint16_t address, bool value);

/**
 * @brief 写单个寄存器
 * @param ctx Modbus上下文
 * @param slave_id 从站地址
 * @param address 寄存器地址
 * @param value 寄存器值
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_write_single_register(modbus_context_t* ctx, uint8_t slave_id,
                                             uint16_t address, uint16_t value);

/**
 * @brief 写多个线圈
 * @param ctx Modbus上下文
 * @param slave_id 从站地址
 * @param start_address 起始地址
 * @param quantity 线圈数量
 * @param coils 线圈状态数组
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_write_multiple_coils(modbus_context_t* ctx, uint8_t slave_id,
                                           uint16_t start_address, uint16_t quantity, const uint8_t* coils);

/**
 * @brief 写多个寄存器
 * @param ctx Modbus上下文
 * @param slave_id 从站地址
 * @param start_address 起始地址
 * @param quantity 寄存器数量
 * @param registers 寄存器值数组
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_write_multiple_registers(modbus_context_t* ctx, uint8_t slave_id,
                                               uint16_t start_address, uint16_t quantity, const uint16_t* registers);

/**
 * @brief 发送原始Modbus请求
 * @param ctx Modbus上下文
 * @param request 请求结构
 * @param response 输出响应结构
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_send_request(modbus_context_t* ctx, const modbus_request_t* request, modbus_response_t* response);

/**
 * @brief 构建Modbus帧
 * @param mode 协议模式
 * @param request 请求结构
 * @param frame 输出帧结构
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_build_frame(modbus_mode_t mode, const modbus_request_t* request, modbus_frame_t* frame);

/**
 * @brief 解析Modbus帧
 * @param mode 协议模式
 * @param frame 帧结构
 * @param response 输出响应结构
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_parse_frame(modbus_mode_t mode, const modbus_frame_t* frame, modbus_response_t* response);

/**
 * @brief 计算CRC16校验值
 * @param data 数据指针
 * @param length 数据长度
 * @return CRC16校验值
 */
uint16_t dtu_modbus_crc16(const uint8_t* data, size_t length);

/**
 * @brief 计算LRC校验值
 * @param data 数据指针
 * @param length 数据长度
 * @return LRC校验值
 */
uint8_t dtu_modbus_lrc(const uint8_t* data, size_t length);

/**
 * @brief 获取Modbus统计信息
 * @param ctx Modbus上下文
 * @param stats 输出统计信息
 * @return DTU_OK 成功，其他值失败
 */
dtu_error_t dtu_modbus_get_stats(modbus_context_t* ctx, modbus_stats_t* stats);

/**
 * @brief 重置Modbus统计信息
 * @param ctx Modbus上下文
 */
void dtu_modbus_reset_stats(modbus_context_t* ctx);

/**
 * @brief 获取功能码字符串
 * @param function_code 功能码
 * @return 功能码字符串
 */
const char* dtu_modbus_function_code_string(modbus_function_code_t function_code);

/**
 * @brief 获取异常码字符串
 * @param exception 异常码
 * @return 异常码字符串
 */
const char* dtu_modbus_exception_string(modbus_exception_t exception);

/**
 * @brief 释放Modbus帧
 * @param frame 帧结构
 */
void dtu_modbus_free_frame(modbus_frame_t* frame);

/**
 * @brief 释放Modbus响应
 * @param response 响应结构
 */
void dtu_modbus_free_response(modbus_response_t* response);

#endif /* DTU_MODBUS_H */
